﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;

using Microsoft.SharePoint;

namespace SharePoint.MoveItems
{
    class MoveItems
    {
        private void WriteToLog(string msg)
        {
            StringBuilder sb = new StringBuilder(DateTime.Now.ToString("u"));
            sb.Append(": ");
            sb.Append(msg);
            sb.Append(Environment.NewLine);

            File.AppendAllText("MoveItems.log", sb.ToString());
        }

        private string GetWebName(SPSite site, string fullFolderUrl)
        {
            WriteToLog("Start: GetWebName");
            string temp = fullFolderUrl.Replace(site.Url + "/", "");
            WriteToLog("GetWebName() 1");
            int startOfListsPlaceholder = temp.IndexOf("/Lists/");
            WriteToLog("GetWebName() 2");
            temp = temp.Remove(startOfListsPlaceholder);
            WriteToLog("End: GetWebName");

            return temp;
        }

        private string GetListName(string fullFolderUrl)
        {
            WriteToLog("Start: GetListName()");
            string ListsSplitter = "/Lists/";
            WriteToLog("GetListName() 1");
            int startOfListName = fullFolderUrl.IndexOf(ListsSplitter) + ListsSplitter.Length;
            WriteToLog("GetListName() 2");
            string temp = fullFolderUrl.Substring(startOfListName);
            WriteToLog("GetListName() 3");
            int nextForwardSlash = temp.IndexOf("/");
            WriteToLog("GetListName() 4");
            temp = temp.Remove(nextForwardSlash);
            WriteToLog("GetListName() 5");
            temp = temp.Replace("%20", " ");
            WriteToLog("End: GetListName()");

            return temp;
        }

        private string GetFolderUrl(SPSite site, string folderUrl)
        {
            WriteToLog("Start: GetFolderUrl()");
            string relativeFolderUrl = GetFolderRelativePath(folderUrl);
            WriteToLog("GetFolderUrl() 1");
            string returnValue = site.Url + relativeFolderUrl;
            WriteToLog("GetFolderUrl() 2");
            returnValue = returnValue.Replace("%20", " ");
            WriteToLog("End: GetFolderUrl()");

            return returnValue;
        }

        private string GetFolderRelativePath(string fullUrl)
        {
            WriteToLog("Start: GetFolderRelativePath()");
            // Relative Folder Url
            string RootFolderSplitter = "RootFolder=";
            WriteToLog("GetFolderRelativePath() 1");
            int startSplitAt = fullUrl.IndexOf(RootFolderSplitter) + RootFolderSplitter.Length;
            int pathLength; 

            int indexOfEndSplitAt = fullUrl.IndexOf('&', startSplitAt);
            WriteToLog("GetFolderRelativePath() 2");
            if (indexOfEndSplitAt < 0)
            {
                WriteToLog("GetFolderRelativePath() 3");
                // 'RootFolder' is the last item in the query string
                pathLength = fullUrl.Length - startSplitAt;
            }
            else
            {
                WriteToLog("GetFolderRelativePath() 4");
                // 'RootFolder' has a variable after it in the query string
                pathLength = indexOfEndSplitAt - startSplitAt;
            }

            WriteToLog("GetFolderRelativePath() 5");
            string relativeFolderUrl = fullUrl.Substring(startSplitAt, pathLength);
            WriteToLog("GetFolderRelativePath() 6");
            relativeFolderUrl = relativeFolderUrl.Replace("%20", " ");
            WriteToLog("GetFolderRelativePath() 7");
            relativeFolderUrl = relativeFolderUrl.Replace("%2f", "/");
            WriteToLog("End: GetFolderRelativePath()");

            return relativeFolderUrl;
        }

        public void Move(int numItemsToMove, string targetFolderFullUrl)
        {            
            SPSite site = null;
            SPWeb web = null;

            try
            {
                string msg = "";

                if (!targetFolderFullUrl.Contains("RootFolder="))
                {
                    throw new Exception("The url does not contain the keyword 'RootFolder' which implies that it is not a folder");
                }

                site = new SPSite(targetFolderFullUrl);
                string webName = GetWebName(site, targetFolderFullUrl);
                string targetListName = GetListName(targetFolderFullUrl);
                string sourceListName = targetListName;
                string targetFolderCodeFriendlyUrl = GetFolderUrl(site, targetFolderFullUrl);

                string siteUrl = targetFolderFullUrl;
                WriteToLog("WebName(" + webName + ")");
                web = site.AllWebs[webName];
                WriteToLog("ListName(" + sourceListName + ")");
                SPList sourceList = web.Lists[sourceListName];
                SPList targetList = web.Lists[targetListName];

                if (targetList.BaseType != SPBaseType.GenericList)
                {
                    throw new Exception("This list is not a Generic List.");
                }

                List<Guid> itemsToMove = new List<Guid>();

                #region Get Items to Move                
                int itemsFound = 0;
                StringBuilder ids =  new StringBuilder();
                foreach (SPListItem item in sourceList.Items)
                {
                    if (item.FileSystemObjectType != SPFileSystemObjectType.Folder)
                    {
                        // Item is in the root folder
                        if (item.Url.Split('/').Length == 3)
                        {
                            itemsFound++;

                            itemsToMove.Add(item.UniqueId);
                            ids.Append(item.ID.ToString() + ",");

                        }
                        // Break out of loop if num items to copy has been met
                        if (numItemsToMove == itemsFound)
                        {                            
                            ids.Remove(ids.Length -1, 1); // remove last comma
                            break;
                        }
                    }
                }
                #endregion

                // WriteToLog
                msg = "#### START --> WebName(" + webName + ") "
                    + "ListName(" + targetListName + ") "
                    + "TargetFolderFullUrl(" + targetFolderFullUrl + ") ";
                WriteToLog(msg);

                msg = "Num Items to Move(" + itemsFound + ") "
                    + "IDs of Items to Move (" + ids + ")";
                WriteToLog(msg);

                #region Move Items
                int itemsMovedCount = 1;
                foreach (Guid guid in itemsToMove)
                {
                    // Item to move
                    SPListItem item = sourceList.Items[guid];

                    // Create New Item                            
                    SPListItem newItem = targetList.Items.Add(targetFolderCodeFriendlyUrl, SPFileSystemObjectType.File, null);

                    // WriteToLog
                    msg = itemsMovedCount.ToString()
                        + " of " + itemsFound.ToString() + " "
                        + "ID(" + item.ID + ") "
                        + " Before Copy "                        
                        + item.Title;
                    WriteToLog(msg);
                    
                    #region Loop through Version History

                    for (int versionCount = item.Versions.Count - 1; versionCount >= 0; versionCount--)
                    {
                        #region Copy Fields
                        foreach (SPField field in item.Versions[versionCount].Fields)
                        {
                            if (
                                (
                                    field.InternalName == "Modified"
                                    || field.InternalName == "Editor" // Modified By
                                    || field.InternalName == "Author" // Created By
                                    || field.InternalName == "Created"
                                )
                                ||
                                (!field.ReadOnlyField && field.InternalName != "Attachments")
                                )
                            {
                                if (
                                    item.Versions[versionCount][field.InternalName] != null
                                    &&
                                    item.Versions[versionCount][field.InternalName].GetType() == typeof(DateTime))
                                {
                                    DateTime date = (DateTime)item.Versions[versionCount][field.InternalName];
                                    date = date.ToLocalTime();
                                    newItem[field.InternalName] = date;
                                }
                                else
                                {
                                    newItem[field.InternalName] = item.Versions[versionCount][field.InternalName];
                                }

                            }
                        }
                        #endregion
                        
                        newItem.Update();
                    }
                    #endregion

                    // WriteToLog
                    msg = itemsMovedCount.ToString()
                        + " of " + itemsFound.ToString() + " "                       
                        + "ID(" + item.ID + ") "
                        + " After Copy "
                        + item.Title;
                    WriteToLog(msg);

                    // WriteToLog (after delete)
                    msg = itemsMovedCount.ToString()
                        + " of " + itemsFound.ToString() + " "
                        + "ID(" + item.ID + ") "
                        + " After Delete "
                        + item.Title;

                    item.Delete();

                    // WriteToLog (after delete)
                    WriteToLog(msg);

                    itemsMovedCount++;
                }
                #endregion
            }
            catch (Exception ex)
            {
                WriteToLog("Error: " + ex.Message + " " + ex.StackTrace);
                throw;
            }
            finally
            {
                site = null;
                web = null;
            }
        }
    }
}
